package com.cf.limit.core.frequency;

import com.cf.constant.EnumReturnCode;
import com.cf.exception.BizException;
import com.cf.limit.core.EnumCheckName;
import com.cf.limit.core.LimitStore;
import com.cf.limit.core.RequestChecker;
import com.cf.limit.core.RequestLimit;
import com.cf.limit.core.service.BlackService;
import com.cf.util.RequestUtil;
import com.cf.util.SpringBeanUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.util.Base64;

/**
 * cf-game-IpLimitChecker
 *
 * @author <a href="2428922347@qq.com">Zhu mingming</a>
 * @info
 * @since 2018/4/23 上午 11:09
 */
@Slf4j
public class IpLimitChecker implements RequestChecker {

    @Autowired
    private BlackService blackService;

    private String getMinutKey(String ip) throws UnsupportedEncodingException {
        return "IpLimitChecker-Minute-" + Base64.getEncoder().encodeToString(ip.getBytes("utf-8"));
    }

    private String getHourKey(String ip) throws UnsupportedEncodingException {
        return "IpLimitChecker-hour-" + Base64.getEncoder().encodeToString(ip.getBytes("utf-8"));
    }

    private String getDayKey(String ip) throws UnsupportedEncodingException {
        return "IpLimitChecker-day-" + Base64.getEncoder().encodeToString(ip.getBytes("utf-8"));
    }

    private String getWeekKey(String ip) throws UnsupportedEncodingException {
        return "IpLimitChecker-week-" + Base64.getEncoder().encodeToString(ip.getBytes("utf-8"));
    }

    private String getMonthKey(String ip) throws UnsupportedEncodingException {
        return "IpLimitChecker-month-" + Base64.getEncoder().encodeToString(ip.getBytes("utf-8"));
    }

    private String getYearKey(String ip) throws UnsupportedEncodingException {
        return "IpLimitChecker-year-" + Base64.getEncoder().encodeToString(ip.getBytes("utf-8"));
    }


    public String getIp(Object[] originalData) throws BizException {
        if (originalData == null)
            throw new BizException(EnumReturnCode.ERROR.getCode(), "参数缺失！无法生成IpCheckBean");

        for (Object originalDatum : originalData) {
            if (originalDatum == null)
                continue;
            if (originalDatum instanceof HttpServletRequest) {
                return RequestUtil.getIpAddr((HttpServletRequest) originalDatum);
            }
        }
        throw new BizException(EnumReturnCode.ERROR.getCode(), "参数缺失！无法找到Ip");
    }

    @Override
    public boolean check(String checkKey, RequestLimit requestLimit) throws UnsupportedEncodingException {

        if (checkKey == null) {
            throw new BizException(EnumReturnCode.ERROR.getCode(), "参数缺失！未获取到");
        }

        if (checkIsInLimit(getMinutKey(checkKey), requestLimit.minute(), 60)
                && checkIsInLimit(getHourKey(checkKey), requestLimit.hour(), 60 * 60)
                && checkIsInLimit(getDayKey(checkKey), requestLimit.day(), 60 * 60 * 24)
                && checkIsInLimit(getWeekKey(checkKey), requestLimit.week(), 60 * 60 * 24 * 7)
                && checkIsInLimit(getMonthKey(checkKey), requestLimit.month(), 60 * 60 * 24 * 30)
                && checkIsInLimit(getYearKey(checkKey), requestLimit.year(), 60 * 60 * 24 * 365)
                ) {
            log.info("IpLimitChecker 检测成功！允许执行。。。");
            return true;
        } else {
            blackService.addBlack(checkKey);
            return false;
        }

    }


    private boolean checkIsInLimit(String checkKey, Integer ipMinuteLimit, Integer timeStep) {
        LimitStore jedis = SpringBeanUtil.getBean(LimitStore.class);
        Long incr = jedis.incr(checkKey);
        if (incr == 1) {
            jedis.expire(checkKey, timeStep);
        }
        if (incr <= ipMinuteLimit) {
            return true;
        } else {
            log.warn("超出限制，IpLimitChecker【{}】【{}】返回false", checkKey, ipMinuteLimit);
            return false;
        }
    }

}
